#include "sbalance.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <limits.h>

int rule_num;
struct sb_forward_rule* rules[CONF_RULE_MAX_NUMS];

static int g_conf_line;

void sb_str_erase_space(char *str)
{
	int i, j;
	int len = strlen(str);

	for (i = 0, j = 0; i < len && j < len; /*void*/) {
		if (str[j] == ' ' || str[j] == '\t' || str[j] == '\r' || str[j] == '\n') {
			j++;
		}
		else {
			str[i++] = str[j++];
		}
	}
	str[i] = '\0';
}

void sb_str_erase_comment(char *str)
{
	char *c = NULL;

	c = index(str, '#');
	if (c != NULL) {
		*c = '\0';
	}
}

#define SB_STATE_EMPTY				0
#define SB_STATE_RULE				1
#define SB_STATE_LEFT_BRACE			2
#define SB_STATE_RIGHT_BRACE		3
#define SB_STATE_TIMEOUT			4
#define SB_STATE_SERVER				5
#define SB_STATE_CLIENT				6
#define SB_STATE_LISTEN				7
#define SB_STATE_LEFT_SMALLBRACE	8
#define SB_STATE_RIGHT_SMALLBRACE	9

#define SB_TAG_RULE	"rule"
#define SB_TAG_SERVER	"server"
#define SB_TAG_CLIENT	"client:"
#define SB_TAG_CONNECT_TIMEOUT		"connect_timeout:"
#define SB_TAG_KEEPALIVE_TIMEOUT	"keepalive_timeout:"
#define SB_TAG_ACCEPT_DELAY		"accept_delay:"
#define SB_TAG_BALANCE		"balance:"
#define SB_TAG_LOGPATHFILENAME		"logfile:"
#define SB_TAG_LISTEN	"listen:"
#define SB_TAG_LEFT_BRACE	"{"	
#define SB_TAG_RIGHT_BRACE	"}"	
#define SB_TAG_LEFT_SMAILLBRACE	"("	
#define SB_TAG_RIGHT_SMAILLBRACE	")"	

#define SB_IP_RANGE_TYPE	1
#define SB_IP_SIMPLE_TYPE	2

#define SB_TIMEOUT_CONNECT_TYPE		1
#define SB_TIMEOUT_KEEPALIVE_TYPE	2
#define SB_DELAY_ACCEPT			3

int sb_conf_parse_ip_range(char *buf, int *start, int *end)
{
	if (strcmp(buf, "*") == 0) {
		*start = CONF_INT_ANY;
		*end = CONF_INT_ANY;
		
		return SB_OK;
	}
	else if (buf[0] == '[' && buf[strlen(buf) - 1] == ']') {
		char *c = NULL;
		*start = -1;
		*end = -1;
		
		c = index(buf, '-');
		if (c) {
			sscanf(buf, "[%d-%d]", start, end);
			if (*start >= 0 && *start <= 255 && *end >= 0 && *end <= 255) {
				if (*end < *start)
					return SB_ERROR;

				return SB_OK;	
			}
		}
	}
	else {
		sscanf(buf, "%d", start);	
		if (*start >= 0 && *start <= 255) {
			*end = *start;
			return SB_OK;
		}
	} 

	return SB_ERROR;
} 

/* one ip at most has range number, so like 192.168.[1-2].[1-255] not allow, should split 
   192.168.1.[1-255], 192.168.2.[1-255] 
   192.168.*.[2-3] not allow
   192.168.*.*	   not allow
   192.168.1.*	   not allow
*/
int sb_conf_parse_ip(char *buf, void *addr, int type)
{
	int rc;
	char *c = NULL;
	char ip1[21];
	char ip2[21];
	char ip3[21];
	char ip4[21];
	char port[21];
	int range_num = 0;
	int any_num = 0;

	if (type == SB_IP_RANGE_TYPE) {
		struct sb_conf_range_address *range_addr = (struct sb_conf_range_address*)addr;

		bzero(ip1, sizeof(ip1));
		bzero(ip2, sizeof(ip2));
		bzero(ip3, sizeof(ip3));
		bzero(ip4, sizeof(ip4));
		bzero(port, sizeof(port));

		sscanf(buf, "%[^.].%[^.].%[^.].%[^:]:%s", ip1, ip2, ip3, ip4, port);
		if (strlen(ip1) == 0 || strlen(ip2) == 0 || strlen(ip3) == 0 || strlen(ip4) == 0 || strlen(port) == 0) 
			return SB_ERROR;
		c = index(ip1, '[');
		if (c)	range_num++;
		c = index(ip1, '*');
		if (c)	any_num++;
		c = index(ip2, '[');
		if (c)	range_num++;
		c = index(ip2, '*');
		if (c)	any_num++;
		c = index(ip3, '[');
		if (c)	range_num++;
		c = index(ip3, '*');
		if (c)	any_num++;
		c = index(ip4, '[');
		if (c)	range_num++;
		c = index(ip4, '*');
		if (c)	any_num++;

		if (range_num >= 2 || (range_num == 1 && any_num > 0) || (any_num >= 1 && any_num != 4)) 
			return SB_ERROR;

		c = NULL;

		rc = sb_conf_parse_ip_range(ip1, &range_addr->ip1_start, &range_addr->ip1_end);
		if (rc != SB_OK) 
			return SB_ERROR;
		rc = sb_conf_parse_ip_range(ip2, &range_addr->ip2_start, &range_addr->ip2_end);
		if (rc != SB_OK) 
			return SB_ERROR;
		rc = sb_conf_parse_ip_range(ip3, &range_addr->ip3_start, &range_addr->ip3_end);
		if (rc != SB_OK) 
			return SB_ERROR;
		rc = sb_conf_parse_ip_range(ip4, &range_addr->ip4_start, &range_addr->ip4_end);
		if (rc != SB_OK) 
			return SB_ERROR;

		if (strlen(port) == 1 && port[0] == '*') {
			range_addr->port = CONF_INT_ANY;
		}
		else {
			errno = 0;
			range_addr->port = strtol(port, &c, 10);
			if (*c != '\0')    
				return SB_ERROR;
		}
//strcpy(range_addr->range_ip, buf);
		sscanf(buf, "%[^:]", range_addr->range_ip);
		if (any_num == 4) {
			range_addr->num = CONF_INT_ANY;
		}
		else { 
			range_addr->num = (range_addr->ip1_end - range_addr->ip1_start + 1) *
						(range_addr->ip2_end - range_addr->ip2_start + 1) *
						(range_addr->ip3_end - range_addr->ip3_start + 1) *
						(range_addr->ip4_end - range_addr->ip4_start + 1);
		}

		return SB_OK;
	}
	else if (type == SB_IP_SIMPLE_TYPE) {
		struct sb_conf_simple_address *simple_addr = (struct sb_conf_simple_address*)addr;
		
		simple_addr->ip1 = -1;
		simple_addr->ip2 = -1; 
		simple_addr->ip3 = -1; 
		simple_addr->ip4 = -1; 
		simple_addr->port = -1; 

		if (strstr(buf, "*.*.*.*")) {
			sscanf(buf, "*.*.*.*:%d", &simple_addr->port);
			if (simple_addr->port == -1) 
				return SB_ERROR;

			simple_addr->ip1 = CONF_INT_ANY;
			simple_addr->ip2 = CONF_INT_ANY;
			simple_addr->ip3 = CONF_INT_ANY;
			simple_addr->ip4 = CONF_INT_ANY;
			strcpy(simple_addr->simple_ip, "*.*.*.*");

			return SB_OK;
		}
		else {
			sscanf(buf, "%d.%d.%d.%d:%d", &simple_addr->ip1, &simple_addr->ip2, &simple_addr->ip3, &simple_addr->ip4, &simple_addr->port);
			if (simple_addr->ip1 >= 0 && simple_addr->ip1 <= 255 && simple_addr->ip2 >= 0 && simple_addr->ip2 <= 255 
				&& simple_addr->ip3 >= 0 && simple_addr->ip3 <= 255 && simple_addr->ip4 >= 0 && simple_addr->ip4 <= 255 
				&& simple_addr->port > 0 )
			{
//strcpy(simple_addr->simple_ip, buf);
				sscanf(buf, "%[^:]", simple_addr->simple_ip);
				return 	SB_OK;
			}
			else {
				return SB_ERROR;
			}
		}
	}
	else {
		return SB_ERROR;
	}
}

int sb_conf_sub_parse_timeout(FILE *file, char *buf, struct sb_forward_rule *rule, char *error_msg, int timeout_type)
{
	int rc = 0;
	char *ptr = NULL;	
	char str_timeout[51], str_scale[21];
	int *timeout_ms = NULL;
	
	if (timeout_type == SB_TIMEOUT_CONNECT_TYPE) {
		ptr = buf + strlen(SB_TAG_CONNECT_TIMEOUT);
		timeout_ms = &rule->connect_timeout;
	}
	else if (timeout_type == SB_TIMEOUT_KEEPALIVE_TYPE ) {
		ptr = buf + strlen(SB_TAG_KEEPALIVE_TIMEOUT);
		timeout_ms = &rule->keepalive_timeout;
	}
	else 
		return SB_ERROR;
	
	sscanf(ptr, "%[0-9]%s", str_timeout, str_scale);
	
	*timeout_ms = strtol(str_timeout, NULL, 10);
	if (strcasecmp(str_scale, "ms") == 0) {
		/* do nothing */
	}
	else if (strcasecmp(str_scale, "s") == 0) {
		*timeout_ms = *timeout_ms * 1000;
	}
	else {
		strcpy(error_msg, "timeout's scale not correct");
		return SB_ERROR;
	}

	return SB_OK;
}

int sb_conf_sub_parse_env_key_value(FILE *file, char *buf, struct sb_cycle_env *env, char *error_msg, int type)
{
        int rc = 0;
        char *ptr = NULL;
        char str_timeout[51], str_scale[21];
        int *timeout_ms = NULL;

        if (type == SB_DELAY_ACCEPT) {
                ptr = buf + strlen(SB_TAG_ACCEPT_DELAY);
                timeout_ms = &env->accept_delay_timeout;
        }
        else
                return SB_ERROR;

        sscanf(ptr, "%[0-9]%s", str_timeout, str_scale);

        *timeout_ms = strtol(str_timeout, NULL, 10);
        if (strcasecmp(str_scale, "ms") == 0) {
                /* do nothing */
        }
        else if (strcasecmp(str_scale, "s") == 0) {
                *timeout_ms = *timeout_ms * 1000;
        }
        else {
                strcpy(error_msg, "timeout's scale not correct");
                return SB_ERROR;
        }

        return SB_OK;
}

int sb_conf_sub_parse_balance(FILE *file, char *buf, struct sb_forward_rule *rule, char *error_msg)
{
	char *ptr = buf + strlen(SB_TAG_BALANCE);
/***
#define BALANCE_MODE_RR      
#define BALANCE_MODE_WEIGHT 
#define BALANCE_MODE_IPHASH    
BALANCE_MODE_RANDOM		
***/
	if (strcmp(ptr, BALANCE_MODE_RR) == 0 || strcmp(ptr, BALANCE_MODE_WEIGHT) == 0  || 
		strcmp(ptr, BALANCE_MODE_IPHASH) == 0 || strcmp(ptr, BALANCE_MODE_RANDOM) == 0) 
	{
		strcpy(rule->balance_mode, ptr);
		return SB_OK;
	}
	else {
		return SB_ERROR;
	}
}
int sb_conf_sub_parse_logfile(FILE *file, char *buf, struct sb_forward_rule *rule, char *error_msg)
{
        char *ptr = buf + strlen(SB_TAG_LOGPATHFILENAME);
	strcpy(rule->log_pathfilename, ptr);

	return SB_OK;
}

int sb_conf_do_sub_parse_addr_group(FILE *file, char *buf, struct sb_forward_rule *rule, char *error_msg, int group_type)
{
	char *ptr = NULL;
	char *c = NULL;
	char line_buf[1025];
	int read_next_line_flag = 0;
	int rc;
	int buf_len;

	strcpy(line_buf, buf);
	buf_len = strlen(line_buf);
	ptr = line_buf;
	if (group_type == SB_STATE_CLIENT ) {
		ptr += strlen(SB_TAG_CLIENT);	
	}
        else if (group_type == SB_STATE_LISTEN ) {
		ptr += strlen(SB_TAG_LISTEN);	
	}

	if (line_buf[buf_len - 1] == '\\') {
		read_next_line_flag = 1;
		line_buf[buf_len - 1] = ',';
	}
	
	while (ptr <  line_buf + buf_len || read_next_line_flag == 1) {
		char tmp_ip_buf[101];
		bzero(tmp_ip_buf, sizeof(tmp_ip_buf));

		c = index(ptr, ',');
	
		if (c) {
			memcpy(tmp_ip_buf, ptr, c - ptr);
		}
		else {
			/* read new line */
			if (read_next_line_flag == 1) {
				memset(line_buf, 0x00, sizeof(line_buf));
				while(fgets(line_buf, 1024, file) != NULL) {
					g_conf_line++;
					sb_str_erase_space(line_buf);
					if (strlen(line_buf) == 0 && line_buf[0] == '#')
						continue;
					sb_str_erase_comment(line_buf);		
					break;
				}
				if (strlen(line_buf) == 0) {
					return SB_ERROR;	
				}
				else {
					buf_len = strlen(line_buf);
					ptr = line_buf;

					read_next_line_flag = 0;
					if (line_buf[buf_len - 1] == '\\') {
						read_next_line_flag = 1;
						line_buf[buf_len - 1] = ',';
					}	

					if (line_buf[0] == ',')	ptr++;
				}
				/* should continue */
				continue;
			}
			else {
				/* possible, last line and last record */
				memcpy(tmp_ip_buf, ptr, line_buf + buf_len - ptr);
			}
		}

		if (strlen(tmp_ip_buf) == 0) {
			ptr++;
			continue;
		}

		if (group_type == SB_STATE_CLIENT &&  rule->client_num >= CONF_CLIENT_NUM_PERRULE) {
			sprintf(error_msg, "too many(>=%d) client ip address in rule-server", CONF_CLIENT_NUM_PERRULE);
			return SB_ERROR;
		}
		else if (group_type == SB_STATE_LISTEN &&  rule->listen_num >= CONF_LISTEN_NUM_PERRULE) {
			sprintf(error_msg, "too many(>=%d) listen ip address in rule-server", CONF_LISTEN_NUM_PERRULE);
			return SB_ERROR;
		}

		if (group_type == SB_STATE_CLIENT) {
			rc = sb_conf_parse_ip(tmp_ip_buf, &rule->client_addr[rule->client_num], SB_IP_RANGE_TYPE);
			if (rc) {
				return SB_ERROR;
			}
			rule->client_num++;
		}
		else if (group_type == SB_STATE_LISTEN) {
			if (index(tmp_ip_buf, '[') != NULL || index(tmp_ip_buf, ']') != NULL) {
				strcpy(error_msg, "listen ip address can't use '['");
				return SB_ERROR;
			}

			rc = sb_conf_parse_ip(tmp_ip_buf, &rule->listen_addr[rule->listen_num], SB_IP_SIMPLE_TYPE);
			if (rc) {
				return SB_ERROR;
			}
			rule->listen_num++;
		}
		else {
			return SB_ERROR;
		}

		if (c) {
			ptr = c + 1;	
		}
		else {
			ptr = line_buf + buf_len;
		}
	}

	return SB_OK;
}

int sb_conf_sub_parse_listen(FILE *file, char *buf, struct sb_forward_rule *rule, char *error_msg)
{
	if (sb_conf_do_sub_parse_addr_group(file, buf, rule, error_msg, SB_STATE_LISTEN))
		return SB_ERROR;

	return SB_OK;
}

int sb_conf_sub_parse_client(FILE *file, char *buf, struct sb_forward_rule *rule, char *error_msg)
{
	if (sb_conf_do_sub_parse_addr_group(file, buf, rule, error_msg, SB_STATE_CLIENT))
		return SB_ERROR;
	return SB_OK;
}

int sb_conf_sub_parse_server(FILE *file, struct sb_forward_rule *rule)
{
	char buf[1024];
	char error_msg[216];
	char tmp_buf1[216], tmp_buf2[216], tmp_buf3[216];
	int rc = SB_OK;
	int state = SB_STATE_EMPTY;
	int weight, max_fails, fail_timeout;
	struct sb_conf_simple_address *simple_addr = NULL;

	memset(error_msg, 0x00, sizeof(error_msg));
	while (fgets(buf, 1024, file) != NULL) {
		g_conf_line++;
		sb_str_erase_space(buf);
		sb_str_erase_comment(buf);
		if (strlen(buf) == 0 || buf[0] == '#') {
			memset(buf, 0x00, sizeof(buf));
			continue;
		}

		switch(state) {
			case SB_STATE_EMPTY:
				{
					if (strcmp(buf, "{") == 0) {
						state = SB_STATE_LEFT_BRACE;	
						break;
					}
					else {
						rc = SB_ERROR;
						goto E;
					}
				}
			case SB_STATE_LEFT_BRACE:
				{
					if (strcmp(buf, "}")  == 0) {
						if (rule->server_num == 0) {
							sprintf(error_msg, "no server information in rule-server");
							goto E;
						}
						rc = SB_OK;
						return rc;
					}
					else {
						memset(tmp_buf1, 0x00, sizeof(tmp_buf1));
						memset(tmp_buf2, 0x00, sizeof(tmp_buf2));
						memset(tmp_buf3, 0x00, sizeof(tmp_buf3));

						simple_addr = &rule->server_addr[rule->server_num].simple_addr;
						sscanf(buf, "%[^(](%[^)])%s", tmp_buf1, tmp_buf2, tmp_buf3);
						if (strlen(tmp_buf3) != 0) {
							rc = SB_ERROR;
							goto E;
						}
						
						weight = 1; max_fails = 1; fail_timeout = 10000;
						if ( (index( buf, '(' ) == NULL) + (index( buf, ')' ) == NULL) != 1 ) {
							char *p = NULL;
							char attr[51], a[51], b[51];

							rc = sb_conf_parse_ip(tmp_buf1, simple_addr, SB_IP_SIMPLE_TYPE);
							if (rc != SB_OK) {
								rc = SB_ERROR;
								goto E;
							}
							if (strlen(tmp_buf2) != 0) {
								p = strtok(tmp_buf2, ";");	
								while(p) {
									memset(attr, 0x00, sizeof(attr));
									memset(a, 0x00, sizeof(a));
									memset(b, 0x00, sizeof(b));
									sscanf(p, "%[^=]=%[0-9]%s", attr, a, b);
									if (strcmp(attr, "weight") == 0) {
										weight = atoi(a);
									} 
									else if (strcmp(attr, "max_fails") == 0) {
										max_fails = atoi(a);
									}
									else if (strcmp(attr, "fail_timeout") == 0) {	
										if (strcmp(b, "s") == 0) {
											fail_timeout = atoi(a) * 1000;
										}
										else if (strcmp(b, "ms") == 0) {
											fail_timeout = atoi(a);
										}
										else {
											rc = SB_ERROR;
											goto E;
										}
									}
									else {
										rc = SB_ERROR;
										goto E;
									}
									p = strtok(NULL, ";");	
								}
							}

							rule->server_addr[rule->server_num].weight = weight;
							rule->server_addr[rule->server_num].fail_timeout = fail_timeout;
							rule->server_addr[rule->server_num].max_fails = max_fails;
							rule->server_num++;

							if (rule->server_num >= CONF_SERVER_NUM_PERRULE) {
								sprintf(error_msg, "too many(>=%d) server ip address in rule-server", 
												CONF_SERVER_NUM_PERRULE);
								rc = SB_ERROR;
								goto E;
							}
						}
						else {
							rc = SB_ERROR;
							goto E;
						}

					}
				}
		}

	}


	if (rc == SB_OK) {
		return rc;
	}

E:
	if (rc == SB_ERROR) {
		ErrorOutput("near line[%d]: \"%s\" parse failed", g_conf_line, buf);
		ErrorOutput("error message:%s", error_msg);
	}

	return rc;

	return SB_OK;
}

int sb_parse_main_conf(struct sb_cycle_env *env, char *filename)
{
	char buf[1025];
	char error_msg[512];
	FILE *file = NULL;
	int rule_index;
	int state = SB_STATE_EMPTY;
	struct sb_forward_rule *new_rule = NULL;
	int rc = SB_OK;

	file = fopen(filename, "r");
	if (file == NULL) {
		ErrorOutput("can't find %s or have no privilege", filename);
		return SB_ERROR;
	}

	memset(error_msg, 0x00, sizeof(error_msg));
	memset(buf, 0x00, sizeof(buf));

	while (fgets(buf, 1024, file) != NULL) {
		g_conf_line++;
		sb_str_erase_space(buf);	
		sb_str_erase_comment(buf);	
		if (strlen(buf) == 0 || buf[0] == '#') {
			memset(buf, 0x00, sizeof(buf));
			continue;
		}

		switch(state) {
			case SB_STATE_EMPTY:
				{
					if (strncmp(buf, SB_TAG_RULE, strlen(SB_TAG_RULE)) == 0) {
						char *c = NULL;
						int name_len;

						new_rule = (struct sb_forward_rule *)malloc(sizeof(struct sb_forward_rule));
						memset(new_rule, 0x00, sizeof(struct sb_forward_rule));
						state = SB_STATE_RULE;

						/* parse rule name */
						c = index(buf, '-');
						if (c == NULL || c == buf + strlen(buf) - 1) {
							strcpy(error_msg, "not find rule name");
							rc = SB_ERROR;
						}

						name_len = buf + strlen(buf) - 1 - c;
						if (name_len > CONF_RULE_NAME_MAX_LEN) {
							strcpy(error_msg, "rule name' length bigger than 50");
							rc = SB_ERROR;
						}
						else {
							strcpy(new_rule->rule_name, c + 1);
						}
					}
                                        else if (strncmp(buf, SB_TAG_ACCEPT_DELAY, strlen(SB_TAG_ACCEPT_DELAY)) == 0) {
                                                rc = sb_conf_sub_parse_env_key_value(file, buf, env, error_msg, SB_DELAY_ACCEPT);
                                                if (rc) {
                                                        rc = SB_ERROR;
                                                        goto E;
                                                }

                                        }
					else {
						rc = SB_ERROR;
						goto E;
					}
					break;	
				}
			case SB_STATE_RULE:
				{
					if (strcmp(buf, SB_TAG_LEFT_BRACE) == 0) {
						state = SB_STATE_LEFT_BRACE;
					}
					break;
				}
			case SB_STATE_LEFT_BRACE:
				{
					if (strcmp(buf, SB_TAG_SERVER)== 0) {
						rc = sb_conf_sub_parse_server(file, new_rule);
						if (rc) {
							rc = SB_ERROR;
							goto F;
						}
					}
					else if(strncmp(buf, SB_TAG_CLIENT, strlen(SB_TAG_CLIENT)) == 0) {
						rc = sb_conf_sub_parse_client(file, buf, new_rule, error_msg);
						if (rc) {
							rc = SB_ERROR;
							goto E;
						}	
					}
					else if (strncmp(buf, SB_TAG_LISTEN, strlen(SB_TAG_LISTEN)) == 0) {
						rc = sb_conf_sub_parse_listen(file, buf, new_rule, error_msg);
						if (rc) {
							rc = SB_ERROR;
							goto E;
						}
					}
					else if (strncmp(buf, SB_TAG_CONNECT_TIMEOUT, strlen(SB_TAG_CONNECT_TIMEOUT)) == 0) {
						rc = sb_conf_sub_parse_timeout(file, buf, new_rule, error_msg, SB_TIMEOUT_CONNECT_TYPE);
						if (rc) {
							rc = SB_ERROR;
							goto E;
						}
					}
					else if (strncmp(buf, SB_TAG_KEEPALIVE_TIMEOUT, strlen(SB_TAG_KEEPALIVE_TIMEOUT)) == 0) {
						rc = sb_conf_sub_parse_timeout(file, buf, new_rule, error_msg, SB_TIMEOUT_KEEPALIVE_TYPE);
						if (rc) {
							rc = SB_ERROR;
							goto E;
						}
					}
					else if (strcmp(buf, SB_TAG_RIGHT_BRACE) == 0) {
						if (strlen(new_rule->rule_name) == 0 || new_rule->listen_num <= 0 ||
								new_rule->client_num <= 0 || new_rule->server_num <= 0 ) 
						{
							rc = SB_ERROR;
							strcpy(error_msg, "every rule need rule name, listen, client, server parameter"); 
							goto E;
						}
						else {
							/* add rule */
							state = SB_STATE_EMPTY;
							env->rules[env->rule_num] = new_rule;
							env->rule_num++;
						}
					}
					else if (strncmp(buf, SB_TAG_BALANCE, strlen(SB_TAG_BALANCE)) == 0) {
						rc = sb_conf_sub_parse_balance(file, buf, new_rule, error_msg);
						if (rc) {
							rc = SB_ERROR;
							goto E;
						}		
					}
					else if (strncmp(buf, SB_TAG_LOGPATHFILENAME, strlen(SB_TAG_LOGPATHFILENAME)) == 0) {
						rc = sb_conf_sub_parse_logfile(file, buf, new_rule, error_msg);
						if (rc) {
							rc = SB_ERROR;
							goto E;
						}		
					}
					else {
						rc = SB_ERROR;
						strcpy(error_msg, "invalid tag");
						goto E;
					}

					break;
				}
		}

		memset(buf, 0x00, sizeof(buf));
	}

	if (state != SB_STATE_EMPTY) {
		rc = SB_ERROR;
		strcpy(error_msg, "file end not correct");
	}
F:
	fclose(file);
	return rc;

E:
	fclose(file);
	if (rc == SB_ERROR) {
		ErrorOutput("near line[%d]: \"%s\" parse failed", g_conf_line, buf);
		ErrorOutput("error message:%s", error_msg);
	}

	return rc;
}

int sb_conf_show(struct sb_cycle_env *env)
{
	int rc = SB_OK; 
	int i, j;
	
	printf("======================ENV CONFIG START====================\n");
	printf("accept_delay: %d\n", env->accept_delay_timeout);
	printf("======================ENV CONFIG END====================\n");

	printf("======================FORWAR RULES START====================\n");
	printf("total rules: %d (notice: follow %d represent '*')\n", env->rule_num, CONF_INT_ANY);
	for (i = 0; i < CONF_RULE_MAX_NUMS; i++) {
		if (env->rules[i] == NULL) 
			continue;

		printf("------------------------rule name[%s]-----------------------\n", env->rules[i]->rule_name);	

		printf("balance: %s\n", env->rules[i]->balance_mode);
		printf("connect timeout:");
		printf("%d ms", env->rules[i]->connect_timeout);
		printf("	keepalive timeout:");
		printf("%d ms\n", env->rules[i]->keepalive_timeout);
		printf("logfile: %s\n", env->rules[i]->log_pathfilename);

		printf("[ rule listen %d ]\n", env->rules[i]->listen_num);
		for(j = 0; j < env->rules[i]->listen_num; j++) {
			printf("%s:%d", env->rules[i]->listen_addr[j].simple_ip, env->rules[i]->listen_addr[j].port);
			printf("====>%d.%d.%d.%d:%d\n", env->rules[i]->listen_addr[j].ip1, env->rules[i]->listen_addr[j].ip2,
					env->rules[i]->listen_addr[j].ip3, env->rules[i]->listen_addr[j].ip4,
					env->rules[i]->listen_addr[j].port);
		}

		printf("[ rule client %d ]\n", env->rules[i]->client_num);
		for(j = 0; j < env->rules[i]->client_num; j++) {
			printf("%s ", env->rules[i]->client_addr[j].range_ip);
			printf("====>[%d-%d].[%d-%d].[%d-%d].[%d-%d]:%d\n", env->rules[i]->client_addr[j].ip1_start, env->rules[i]->client_addr[j].ip1_end,
					env->rules[i]->client_addr[j].ip2_start, env->rules[i]->client_addr[j].ip2_end,
					env->rules[i]->client_addr[j].ip3_start, env->rules[i]->client_addr[j].ip3_end,
					env->rules[i]->client_addr[j].ip4_start, env->rules[i]->client_addr[j].ip4_end,
					env->rules[i]->client_addr[j].port );
		}

		printf("[ rule server %d ]\n", env->rules[i]->server_num);
		for(j = 0; j < env->rules[i]->server_num; j++) {
				printf("%s:%d", env->rules[i]->server_addr[j].simple_addr.simple_ip, env->rules[i]->server_addr[j].simple_addr.port);
                printf("=====>%d.%d.%d.%d:%d\t", env->rules[i]->server_addr[j].simple_addr.ip1, env->rules[i]->server_addr[j].simple_addr.ip2,
					env->rules[i]->server_addr[j].simple_addr.ip3, env->rules[i]->server_addr[j].simple_addr.ip4,
                    env->rules[i]->server_addr[j].simple_addr.port);
				printf("weight= %d, max_fails = %d, fail_timeout = %dms\n", env->rules[i]->server_addr[j].weight, 
					env->rules[i]->server_addr[j].max_fails,
					env->rules[i]->server_addr[j].fail_timeout );
		}
	} 	
	printf("======================FORWAR RULES END=====================\n");
	printf("\n");

	return SB_OK;
}
